#pragma once
#include<string.h>
#include<unordered_map>
#include<functional>
#include <google/protobuf/message.h>
#include"Acceptor.h"
#include"InetAddress.h"
#include"Connection.h"
#include"Callback.h"
#include"Core.h"
namespace wjc {
    using namespace net;
    using  MessagePtr = std::shared_ptr<google::protobuf::Message>;
    class TcpServer {
    public:
        using ThreadInitCallback = std::function<void(Core*)>;
        TcpServer(
            int coreNum,
            const InetAddress& listenAddr,
            const std::string& name);
        ~TcpServer();  // force out-line dtor, for std::unique_ptr members.


        const std::string& ipPort() const { return ipPort_; }
        const std::string& name() const { return name_; }

        /// Starts the server if it's not listenning.
        ///
        /// It's harmless to call it multiple times.
        /// Thread safe.
        void start();

        /// Set connection callback.
        /// Not thread safe.
        void setConnectionCallback(const ConnectionCallback& cb)
        {
            connectionCallback_ = cb;
        }

        /// Set message callback.
        /// Not thread safe.
        void setMessageCallback(const MessageCallback& cb)
        {
            messageCallback_ = cb;
        }

        /// Set write complete callback.
        /// Not thread safe.
        void setWriteCompleteCallback(const WriteCompleteCallback& cb)
        {
            writeCompleteCallback_ = cb;
        }

        void sendToOtherConn(const std::string& msg, const ConnectionPtr& connEx);
        void sendToAllConn(const std::string& msg);

        void sendMsgToOtherConn(MessagePtr& msg, const ConnectionPtr& connEx);
        void sendMsgToAllConn(MessagePtr& msg);

    private:
        /// Not thread safe, but in loop
        void newConnection(int sockfd, const InetAddress& peerAddr);
        /// Thread safe.
        void removeConnection(const ConnectionPtr& conn);
        /// Not thread safe, but in loop
        void removeConnectionInCore(const ConnectionPtr& conn);

        typedef std::unordered_map<std::string, ConnectionPtr> ConnectionMap;

        std::atomic_bool started_;

        const std::string ipPort_;
        const std::string name_;
        int coreNum_;
        std::shared_ptr<Core> mainCore_;  // the acceptor loop

        std::shared_ptr<Acceptor> acceptor_; // avoid revealing Acceptor
        //std::vector<std::shared_ptr<Acceptor>> subAcceptors_; // avoid revealing Acceptor

        ConnectionCallback connectionCallback_;
        MessageCallback messageCallback_;
        WriteCompleteCallback writeCompleteCallback_;

        int nextConnId_=0;
        ConnectionMap connections_;
    };
}
